package com.example.ibsp_demo.controller.homePagePush;

import com.example.ibsp_demo.mapper.content.ContentHotRankMapper;
import com.example.ibsp_demo.mapper.content.ContentMapper;
import com.example.ibsp_demo.mapper.content.PartitionMapper;
import com.example.ibsp_demo.mapper.user.FollowRelationMapper;
import com.example.ibsp_demo.mapper.user.UserInterestMapper;
import com.example.ibsp_demo.mapper.user.UserMapper;
import com.example.ibsp_demo.pojo.dto.homePagePost.SimilarUserDto;
import com.example.ibsp_demo.pojo.entity.content.Content;
import com.example.ibsp_demo.pojo.entity.content.Partition;
import com.example.ibsp_demo.pojo.entity.user.User;
import com.example.ibsp_demo.pojo.entity.user.UserInterest;
import com.example.ibsp_demo.pojo.response.ResponseMessage;
import com.example.ibsp_demo.service.location.ILocationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import static java.lang.Math.max;
import static java.lang.Math.min;
import static net.sf.jsqlparser.statement.select.First.Keyword.LIMIT;

@RestController
@RequestMapping("/pushPost")
public class HomePagePostPushController {

    private int PAGE_SIZE = 5; // 每页加载数量
    private double RECOMMEND_RATIO = 0.7; // 兴趣内容比例
    private double RANDOM_RATIO = 0.3; // 随机内容比例
    private int HOT_RANK_LIMIT = 10;
    private int SIMILAR_RANK_LIMIT = 3;

    private static final int MAX_VIEW_HISTORY_LENGTH = 20;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserInterestMapper  userInterestMapper;

    @Autowired
    private ContentMapper contentMapper;

    @Autowired
    private FollowRelationMapper followRelationMapper;

    @Autowired
    private PartitionMapper partitionMapper;

    @Autowired
    private ContentHotRankMapper contentHotRankMapper;

    @Autowired
    private ILocationService locationService;

    // 存储用户浏览历史 (用户ID -> 已浏览帖子ID列表)
    private static final Map<Integer, List<Integer>> userViewHistory = new ConcurrentHashMap<>();

    // 存储用户最后浏览时间 (用户ID -> 时间戳)
    private static final Map<Integer, Long> userLastViewTime = new ConcurrentHashMap<>();

    private static final Map<Integer,List<Integer>> recommendedUsers = new ConcurrentHashMap<>();
    // 存储用户的推荐计数器 (用户ID -> 计数器)
    private static final Map<Integer, Integer> recommendationCounter = new ConcurrentHashMap<>();

    // 存储用户的分页状态 (用户ID -> 当前页码)
    private static final Map<Integer, Integer> userPageState = new ConcurrentHashMap<>();

    // 检查是否为新用户，存在则返回用户信息，不存在则返回新用户标志
    @GetMapping("/checkNewUser/{uid}")
    public ResponseMessage<User> checkNewUser(@PathVariable("uid") Integer uid) {
        User user = userMapper.selectByUid(uid);
        if(user.getPhone() == null){
            // 返回特殊的状态码或标志，告诉前端这是新用户，需要显示标签页选择弹窗
            return ResponseMessage.success(null);
        }
        // 老用户直接返回用户信息
        return ResponseMessage.error(500,"too old");
    }

    //个性化推送 => 70%为用户选择标签推荐 30%为排序（高比重）内容 （hard）
        // 先硬编码吧，但是如何防止用户刷到已经看过的内容呢？ => (easy+)
    // 获取个性化推荐内容
    // 获取个性化推荐内容（改进版）
    @GetMapping("/recommend/{uid}")
    public ResponseMessage<List<Content>> getRecommendations(
            @PathVariable("uid") int uid,
            @RequestParam(value = "page", defaultValue = "1") int page) {

        // 更新用户分页状态
        userPageState.put(uid, page);

        // 计算本次需要的内容数量
        int recommendCount = (int) (PAGE_SIZE * RECOMMEND_RATIO);
        int randomCount = (int) (PAGE_SIZE * RANDOM_RATIO);

        // 获取用户浏览历史
        List<Integer> viewedContentIds = userViewHistory.getOrDefault(uid, Collections.emptyList());

        // 获取用户兴趣标签
        List<UserInterest> userInterests = userInterestMapper.selectByUid(uid);

        // 获取兴趣内容（分页查询）
        List<Content> interests = contentMapper.selectByTagsPaged(
                userInterests,
                viewedContentIds,
                (page - 1) * recommendCount,
                recommendCount
        );

        // 动态调整随机内容数量
        int actualRandomCount = PAGE_SIZE - interests.size();
        if (actualRandomCount < 0) actualRandomCount = 0;

        // 获取随机内容（排除已浏览的）
        List<Content> randoms = Collections.emptyList();
        if (actualRandomCount > 0) {
            randoms = contentMapper.getRandomContentsExcluding(
                    viewedContentIds,
                    actualRandomCount
            );
        }

        // 合并结果
        List<Content> result = new ArrayList<>();
        result.addAll(interests);
        result.addAll(randoms);

        // 记录浏览历史
        List<Integer> newViewedIds = result.stream()
                .map(Content::getCtid)
                .toList();

        List<Integer> viewHistory = userViewHistory.computeIfAbsent(uid, k -> new ArrayList<>());
        viewHistory.addAll(newViewedIds);

        // 维护浏览历史长度
        if (viewHistory.size() > MAX_VIEW_HISTORY_LENGTH) {
            int excess = viewHistory.size() - MAX_VIEW_HISTORY_LENGTH;
            viewHistory.subList(0, excess).clear();
        }

        // 更新最后浏览时间
        userLastViewTime.put(uid, System.currentTimeMillis());

        return ResponseMessage.success(result);
    }


    //发现：移动到全部分区对应推送
        //普通分区（easy） => 0秒猜出get (easy)
        //特殊分区如：同城 ， 关注
            // 关注简单（easy） => 直接关注表 =>get
            // 但是同城要调用什么api呢？（hard）=> 也是get ,但是这里要调用地理位置的api的service
    // 获取分区内容（改进版）
    @GetMapping ("/partition")
    public ResponseMessage<List<Content>> getPartitions(
            @RequestParam("uid") int uid,
            @RequestParam("partitionName") String partitionName,
            @RequestParam("longitude") Double longitude,
            @RequestParam("latitude") Double latitude) { // 移除分页参数

        try {
            // 获取用户浏览历史
            List<Integer> viewedContentIds = userViewHistory.getOrDefault(uid, Collections.emptyList());

            List<Content> contents = new ArrayList<>();

            // 处理特殊分区：同城和关注
            if ("同城".equals(partitionName)) {
                String userLocation = locationService.getCityByCoordinates(longitude, latitude);
                if (userLocation != null && !userLocation.isEmpty()) {
                    userLocation = userLocation.substring(0, userLocation.length() - 1);
                    // 获取全部分区内容（不分页）
                    contents = contentMapper.selectByLocation(userLocation);
                }
            } else if ("关注".equals(partitionName)) {
                List<Integer> followedIds = followRelationMapper.selectFollowedIdByFollowerId(uid);
                if (!followedIds.isEmpty()) {
                    // 获取全部分区内容（不分页）
                    contents = contentMapper.selectByAuids(followedIds);
                }
            } else {
                Partition targetPartition = partitionMapper.selectByPartitionName(partitionName);
                if (targetPartition != null) {
                    // 获取全部分区内容（不分页）
                    contents = contentMapper.selectByPid(targetPartition.getPid());
                }
            }

            // 记录浏览历史
            List<Integer> newViewedIds = contents.stream()
                    .map(Content::getCtid)
                    .toList();

            List<Integer> viewHistory = userViewHistory.computeIfAbsent(uid, k -> new ArrayList<>());
            viewHistory.addAll(newViewedIds);

            // 维护浏览历史长度
            if (viewHistory.size() > MAX_VIEW_HISTORY_LENGTH) {
                int excess = viewHistory.size() - MAX_VIEW_HISTORY_LENGTH;
                viewHistory.subList(0, excess).clear();
            }

            // 更新最后浏览时间
            userLastViewTime.put(uid, System.currentTimeMillis());

            return ResponseMessage.success(contents);
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseMessage.error(500, "获取分区内容失败: " + e.getMessage());
        }
    }


    // 写热帖榜单：无论对哪个用户来说都是一样的热帖榜单，先展示一段硬编码的热帖（easy ） ，之后通过特殊的算法计算帖子的得分，然后下次刷到的时候推送 （hard）
        //先硬编码吧 =>  get (easy)
    // 热帖榜单接口返回完整内容
    @GetMapping("/hotContent")
    public ResponseMessage<List<Content>> getHotContents(){
        List<Content> hotContents = contentHotRankMapper.selectHotContents(HOT_RANK_LIMIT);
        return ResponseMessage.success(hotContents);
    }


    //如何推荐可能会感兴趣的人 ，需要计算得分（hard）
        //先硬编码一段 => get (easy)
    @GetMapping("/similarUser/{uid}")
    public ResponseMessage<List<SimilarUserDto>> getSimilarUsers(@PathVariable("uid") int uid) {
        try {
            // 1. 获取当前用户已被推荐过的用户列表（初始化空列表避免null）
            List<Integer> alreadyRecommended = recommendedUsers.computeIfAbsent(uid, k -> new ArrayList<>());

            // 2. 获取当前用户的兴趣标签（原逻辑保留）
            List<UserInterest> currentUserInterests = userInterestMapper.selectByUid(uid);
            Set<String> currentUserTags = new HashSet<>();
            if (currentUserInterests != null && !currentUserInterests.isEmpty()) {
                currentUserTags = currentUserInterests.stream()
                        .map(UserInterest::getTag)
                        .collect(Collectors.toSet());
            }

            // 3. 查询其他用户的兴趣标签并计算相似度（原逻辑保留）
            List<UserInterest> otherUsersInterests = userInterestMapper.selectAllExceptByUid(uid);
            Map<Integer, Set<String>> otherUserTagMap = new HashMap<>();
            if (otherUsersInterests != null && !otherUsersInterests.isEmpty()) {
                otherUserTagMap = otherUsersInterests.stream()
                        .collect(Collectors.groupingBy(
                                UserInterest::getUid,
                                Collectors.mapping(UserInterest::getTag, Collectors.toSet())
                        ));
            }

            // 4. 计算用户相似度并排序（原逻辑保留）
            Map<Integer, Integer> userSimilarity = new HashMap<>();
            for (Map.Entry<Integer, Set<String>> entry : otherUserTagMap.entrySet()) {
                int otherUid = entry.getKey();
                Set<String> otherUserTags = entry.getValue();

                // 计算共同标签数量（相似度）
                Set<String> commonTags = new HashSet<>(otherUserTags);
                commonTags.retainAll(currentUserTags);
                userSimilarity.put(otherUid, commonTags.size());
            }

            // 5. 过滤已推荐的用户，并按相似度排序
            List<Integer> candidateUids = userSimilarity.entrySet().stream()
                    .filter(entry -> !alreadyRecommended.contains(entry.getKey())) // 过滤已推荐的用户
                    .sorted((e1, e2) -> Integer.compare(e2.getValue(), e1.getValue())) // 按相似度降序
                    .map(Map.Entry::getKey)
                    .collect(Collectors.toList());

            // 6. 若候选用户不足，补充未推荐的随机用户
// 6. 若候选用户不足，补充未推荐的随机用户
            if (candidateUids.size() < SIMILAR_RANK_LIMIT) {
                // 获取未推荐过的随机用户（修正参数名冲突）
                List<Integer> randomUids = userMapper.selectRandomUidsExcept(uid, SIMILAR_RANK_LIMIT - candidateUids.size())
                        .stream()
                        .filter(otherUid -> !alreadyRecommended.contains(otherUid)) // 参数名改为otherUid
                        .toList();
                candidateUids.addAll(randomUids);
            }

            // 7. 限制最终返回数量，并获取用户信息
            List<Integer> finalUids = candidateUids.stream()
                    .limit(SIMILAR_RANK_LIMIT)
                    .collect(Collectors.toList());
            List<User> similarUsers = userMapper.selectAllByUids(finalUids, SIMILAR_RANK_LIMIT);

            // 8. 过滤敏感信息（原逻辑保留）
            filterSensitiveInfo(similarUsers);

            // 9. 记录本次推荐的用户到历史（更新推荐记录）
            List<Integer> recommendedUids = similarUsers.stream()
                    .map(User::getUid)
                    .toList();
            recommendedUsers.get(uid).addAll(recommendedUids);

            // 10. 转换为DTO并返回
            return ResponseMessage.success(toSimilarUserDto(similarUsers));
        } catch (Exception e) {
            e.printStackTrace();
            return ResponseMessage.error(500, "获取相似用户失败：" + e.getMessage());
        }
    }
    private List<SimilarUserDto> toSimilarUserDto(List<User> randomUsers) {
        List<SimilarUserDto> similarUserDtos = new ArrayList<>();
        randomUsers.forEach(user -> {
            SimilarUserDto similarUserDto = new SimilarUserDto();
            similarUserDto.setUid(user.getUid());
            similarUserDto.setUserInput(user.getUsername());
            similarUserDtos.add(similarUserDto);
        });
        return similarUserDtos;
    }


    // 辅助方法：过滤用户敏感信息（避免返回密码、手机号等）
    private void filterSensitiveInfo(List<User> users) {
        for (User user : users) {
            user.setPasswordHash(null);    // 清除密码哈希
            user.setEmail(null);           // 清除邮箱（根据需求决定是否保留）
            user.setPhone(null);           // 清除手机号（根据需求决定是否保留）
        }
    }


    //一个共同难点：如何控制新内容的产出和不会重复刷到已经看到的内容？（hard）
        // 1. 每个用户都有一个自己的帖子浏览记录，推荐时根据用户的浏览记录进行推荐。
        // 2. 定期更新推荐列表，引入新的内容。
        // 3. 引入用户反馈机制，如点赞、评论等，调整推荐结果。
}
